package lhy.utils;

import lhy.autoparts.pojo.User;
import lhy.autoparts.pojo.UserRole;
import lhy.exception.ForeignKeyException;
import lhy.orm.annotation.Column;
import org.apache.commons.beanutils.BeanUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Consumer;

public class ReflectUtils {
    public static String getClassShortName(Class<?> clz){
        return clz.getSimpleName();
    }
    public static String getClassFullName(Class<?> clz){
        return clz.getCanonicalName();
    }
    public static Class<?> loadClassByName(String className){
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
	public static Field getFieldByName(Class<?> clz,String name) {
		try {
			Field f =clz.getDeclaredField(name);
			f=setAccessible(f);
			return f;
		} catch (NoSuchFieldException | SecurityException e) {
            throw new ForeignKeyException();
		}
	}
    public static String getFieldName(Field field){
        field.setAccessible(true);
        return field.getName();
    }
    //创建新实例
    public static <T> T newInstance(Class<T> modelClass,Class<?>... params){
        try {
            return modelClass.getDeclaredConstructor(params).newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }
    //设置为可见
    public static Field setAccessible(Field field){
        field.setAccessible(true);
        return field;
    }
    //获取变量并设置为可见，必须拥有column注解说明
    public static Field[] getAccessibleFields(Class<?> modelClass){
        return Arrays.stream(modelClass.getDeclaredFields())
                .map(ReflectUtils::setAccessible)
                .filter(f->f.getAnnotation(Column.class)!=null)
                .toArray(Field[]::new);
    }
    public static List<Field> getAccessibleFieldsList(Class<?> modelClass){
        return (List.of(getAccessibleFields(modelClass)));
    }
    //遍历每个变量
    public static void traversalEveryField(Class<?> modelClass,Consumer<Field> funcTodo){
        Arrays.stream(getAccessibleFields(modelClass)).forEachOrdered(funcTodo);
    }
    //设置变量的值
    public static void setFieldValue(Field field,Object objInstance,Object valueToSet){
        try {
            Class<?> clz = field.getType();
            if(valueToSet==null)
                return;
            String val2Set = String.valueOf(valueToSet).replace("¥","").replace("￥","");
            if(clz == String.class){
                field.set(objInstance,valueToSet);
            }else if(clz == int.class)
                field.set(objInstance,Integer.parseInt(val2Set));
            else if(clz == double.class)
                field.set(objInstance,Double.parseDouble(val2Set));
            else if(clz == float.class)
                field.set(objInstance,Float.parseFloat(val2Set));
            else if(clz == long.class)
                field.set(objInstance,Long.parseLong(val2Set));
            else if(clz == char.class)
                field.set(objInstance, (val2Set).charAt(0));
            else if(clz == boolean.class)
                field.set(objInstance,Boolean.parseBoolean(val2Set));
             else if(clz == Date.class){
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
                Date date = formatter.parse(val2Set);
                field.set(objInstance,date);
            }else if(clz== User.class){
                 field.set(objInstance,new User("admin","管理员","admin",new UserRole(1,"管理员","系统管理"),null));
            }else {
                Object o = newInstance(clz);
                Field field1 = clz.getField("id");
                setFieldValue(field1,o,valueToSet);
                field.set(objInstance,o );
            }

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }


    public static <T> T combine2Objects(T a, T b) throws InstantiationException, IllegalAccessException, InvocationTargetException {
        // would require a noargs constructor for the class, maybe you have a different way to create the result.
        T result = (T) a.getClass().newInstance();
        BeanUtils.copyProperties(a, result);
        BeanUtils.copyProperties(b, result);
        return result;
    }
    //获取变量的值
    public static Object getFieldValue(Field field,Object objInstance){
        try {
           return field.get(objInstance);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void setFieldValueFromResultSet(Field field, Object objInstance, ResultSet rs){
        try {
            setFieldValue(field,objInstance, Optional.ofNullable(rs.getObject(getFieldName(field))).orElse("0"));
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}
